package jp.sourceforge.akjrcp.dropsomething;

import java.io.File;
import java.util.List;
import java.util.Map;

import jp.sourceforge.akjrcp.akj_betas.Akj_betasPlugin;
import jp.sourceforge.akjrcp.akj_betas.Messages;
import jp.sourceforge.akjrcp.commons.ui.widget.LayoutDataBuilder;
import jp.sourceforge.akjrcp.dropsomething2.DropFileGenericParameterSetting;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegExecuter;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegOptions;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUI;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUtils;
import jp.sourceforge.akjrcp.ui.FileOverwriteControler;
import jp.sourceforge.akjrcp.ui.GenericParameters;
import jp.sourceforge.akjrcp.ui.GenericParametersFieldEditor;
import jp.sourceforge.akjrcp.ui.GenericParametersEditorDialog;
import jp.sourceforge.akjrcp.ui.GenericParametersEventListener;
import jp.sourceforge.akjrcp.ui.GenericParametersFFMpegPreference;
import jp.sourceforge.akjrcp.ui.GenericParametersOptionUIEditor;
import jp.sourceforge.akjrcp.ui.GenericParametersSaveDialog;
import jp.sourceforge.akjrcp.ui.GenericParametersTableViewer;

import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.PlatformUI;

public abstract class AbstractFFMpegDropSomething extends DirectoryBasedDropSomething implements FFMpegDropSomethingTab{
	protected FileOverwriteControler fileOverwriteControler;//this need she
	public static final String AVISYNTH="avisynth";

	protected GenericParametersFFMpegPreference preference;
	protected GenericParametersTableViewer tableViewer;


	protected GenericParametersOptionUIEditor editor;

	protected Button saveSetting;
	protected Button newSetting;
	
	protected FFMpegExecuter currentFfmpegExecuter;
	protected Label dragHere;

	public AbstractFFMpegDropSomething(Composite parent, int style,String key) {
		super(parent, style,key);
	}

	public class SelectChanged implements ISelectionChangedListener{

		public void selectionChanged(SelectionChangedEvent event) {
			tableSelectionChanged();
		}
		
	}
	
	public Composite createControls(Composite parent) {
		
		Composite composite=new Composite(parent,SWT.NULL);
		GridLayout rootLayout=new GridLayout(1,true);
		rootLayout.marginHeight=2;
		rootLayout.marginWidth=4;
		
		composite.setLayout(rootLayout);
		
		Composite listComposite=new Composite(composite,SWT.NULL);
		GridData listData=LayoutDataBuilder.hintGridData(-1, 110);
		
		listComposite.setLayoutData(listData);
		GridLayout listLayout=new GridLayout(2,false);
		listLayout.marginHeight=0;
		listLayout.marginWidth=0;
		listComposite.setLayout(listLayout);
		
		List list=GenericParametersTableViewer.loadList(getPreferenceStore().getString(getPreferenceKey()+"."+FFMpegDropSomethingTab.SETTINGS));
		
		GridData gd = new GridData(GridData.FILL_BOTH);
		//gd.minimumHeight=40;
		//gd.heightHint=60;
		//gd.grabExcessVerticalSpace=true;
		tableViewer = new GenericParametersTableViewer(listComposite);
		tableViewer.getTable().setLayoutData(gd);
		tableViewer.setGenericParametersList(list);
		
		tableViewer.addSelectionChangedListener(new SelectChanged());
		
		Composite buttons=new Composite(listComposite,SWT.NULL);
		buttons.setLayout(new GridLayout(1,false));
		
		
		newSetting = new Button(buttons,SWT.NULL);
		newSetting.setText(Messages.getString("h264converter.new"));
		newSetting.addSelectionListener(new GenericNew());
		
		
		saveSetting = new Button(buttons,SWT.NULL);
		saveSetting.setText(Messages.getString("h264converter.save"));
		saveSetting.setEnabled(false);
		saveSetting.addSelectionListener(new GenericSave());
		
		//buttonList=new ArrayList();
		//settingList=new ArrayList();
		
		
		
		
		createDirectoryInfo(composite);//old style dir.
		
		
		editor = makeGenericParameterOptionEditor();
		Composite editorComposite=editor.createControls(composite);
		
		editor.addListener(new GenericParametersEventListener(){
			public void updateModified(boolean modified) {
				saveSetting.setEnabled(modified);
			}
			
		});
		updateStatus();
		
		
		Akj_betasPlugin.getDefault().getPluginPreferences().addPropertyChangeListener( new PreferenceStoreMonitor());
		
		//select item
		int defaultSelect=getPreferenceStore().getInt(getPreferenceKey()+SELECTION_INDEX);
		log.info("defaultSelect:"+defaultSelect);
		if(tableViewer.getTable().getItemCount()>defaultSelect){
			tableViewer.getTable().setSelection(Math.max(0,defaultSelect));//this method don't call SelectionChangedListener 
			
			}else{
				if(tableViewer.getTable().getItemCount()>0){
					tableViewer.getTable().setSelection(0);//this method don't call SelectionChangedListener 
				}else{
					log.info("item is empty");
				}
			}
		tableSelectionChanged();
		tableViewer.addSelectionChangedListener(new StoreSelect());
		
		return composite;
	}
	
	public void tableSelectionChanged(){
		GenericParameters parameters;
		saveSetting.setEnabled(false);//changed
		int selection=tableViewer.getTable().getSelectionIndex();
		if(selection>=0){
		log.info("table item changed:"+selection);
		parameters=(GenericParameters) tableViewer.getTable().getItem(tableViewer.getTable().getSelectionIndex()).getData();
		//log.info("size:"+paramList.size());
		}else{
			//setDefault
			parameters=makeDefaultGenericParameters();
		}
		
		Map map=parameters.getParameters();
		
		editor.setParameters(map);
		saveSetting.setEnabled(false);//changed
	}
	public abstract GenericParameters makeDefaultGenericParameters(); 
	

	public class GenericNew implements SelectionListener {

		public void widgetDefaultSelected(SelectionEvent e) {
			
		}

		public void widgetSelected(SelectionEvent e) {
			GenericParametersEditorDialog dialog=new GenericParametersEditorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
			
			int result=dialog.open();
			if(result==Dialog.OK){
				GenericParameters newed=makeDefaultGenericParameters();
				newed.setName(dialog.getName());
				newed.setComment(dialog.getComment());
				
				//setDefault parameter
				tableViewer.getGenericParameters().add(newed);
				tableViewer.refresh();
				
				//save
				GenericParameters infos[] = (GenericParameters[]) tableViewer.getGenericParameters().toArray(new GenericParameters[0]);
				String newValue=GenericParametersFieldEditor.toStoreString(infos);
				getPreferenceStore().setValue(FFMpegSettingPage.EXPORT_FFMPEG_SETTINGS,newValue);
				
				tableViewer.getTable().setSelection(tableViewer.getTable().getItemCount()-1);//select last one.
				tableSelectionChanged();//update items
			}else{
				log.info(result);
			}
		}
	}
	
	
	public abstract GenericParametersOptionUIEditor makeGenericParameterOptionEditor();
	
	
	
	public class GenericSave implements SelectionListener {

		public void widgetDefaultSelected(SelectionEvent e) {
			
		}

		public void widgetSelected(SelectionEvent e) {
		GenericParameters parameter=tableViewer.getCurrentSelection();
		GenericParametersSaveDialog dialog=new GenericParametersSaveDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
		String oldName=parameter.getName();
		if(parameter==null){
		dialog.setName(Messages.getString("dropsomething.newsetting"));	
		}else{
		String newName=tableViewer.copiedName(parameter);
		dialog.setName(newName);
		dialog.setComment(parameter.getComment());
		}
		
		int ret=dialog.open();
		int selection;
		if(ret==Dialog.OK){
			log.info("Save:"+dialog.isSaveOverwrite());
			Map newMap=editor.getParameters();
			if(dialog.isSaveOverwrite()){
//				overwrite or copy
				parameter.setParameters(newMap);
				parameter.setName(oldName);//re set old name.
				parameter.setComment(dialog.getComment());
				selection=tableViewer.getTable().getSelectionIndex();
			}else{
				GenericParameters newParam=new GenericParameters(newMap);
				newParam.setName(dialog.getName());
				newParam.setComment(dialog.getComment());
				
				tableViewer.getGenericParameters().add(newParam);
				tableViewer.refresh();//
				selection=tableViewer.getTable().getItemCount()-1;//added item.
			}
			//store data
			
			GenericParameters infos[] = (GenericParameters[]) tableViewer.getGenericParameters().toArray(new GenericParameters[0]);
			//String oldValue=getPreferenceStore().getString(H264SettingPage.EXPORT_H264_SETTINGS);
			String newValue=GenericParametersFieldEditor.toStoreString(infos);
			//set only difference
			
//			save store
			getPreferenceStore().setValue(FFMpegSettingPage.EXPORT_FFMPEG_SETTINGS,newValue);
			
			
			tableViewer.getTable().setSelection(selection);
			tableSelectionChanged();
			//update value;
		}
		}

	}
	
	public class StoreSelect implements ISelectionChangedListener{

		public void selectionChanged(SelectionChangedEvent event) {
			getPreferenceStore().setValue(getPreferenceKey()+SELECTION_INDEX, tableViewer.getTable().getSelectionIndex());
		}
		
	}
	/*
	public class SavePreferenceStore implements SelectionListener{
		
		public void widgetDefaultSelected(SelectionEvent e) {
			
		}

		public void widgetSelected(SelectionEvent e) {
			storeControl((Control)e.getSource());
		}
	}*/
	
	/*
	public void restoreControl(Control control){
		IPreferenceStore store=getPreferenceStore();
		
		if(control==avisynth){
			
			avisynth.setSelection(store.getBoolean(getPreferenceKey()+"."+AVISYNTH));
			
			}
	}*/
	

	
	public void selectCombo(CCombo combo,String value){
		int s=combo.getItemCount();
		for (int i = 0; i <s; i++) {
			if(combo.getItem(i).equals(value)){
				combo.select(i);
				break;
			}
		}
	}
	
/*
	public void storeControl(Control control){
		IPreferenceStore store=getPreferenceStore();
		
		if(control==avisynth){
			
			
			store.setValue(getPreferenceKey()+"."+AVISYNTH, avisynth.getSelection());
			}/*else if(control==twoPass){
				
				
				store.setValue(getPreferenceKey()+"."+TWO_PASS, twoPass.getSelection());
				}
	}
*/	

	
	
	public String toTime(long bps,long maxMega){
		long bytes=bps/8;
		
		long second=maxMega*1024*1024/bytes;
		long hour=second/3600;
		second=second%3600;
		long min=second/60;
		long sec=second%60;
		
		String hstring=""+hour;
		if(hstring.length()<2){
			hstring="0"+hstring;
		}
		
		String mstring=""+min;
		if(mstring.length()<2){
			mstring="0"+mstring;
		}
		
		String sstring=""+sec;
		if(sstring.length()<2){
			sstring="0"+sstring;
		}
		return hstring+":"+mstring+":"+sstring;
	}

	public void inconvert(File file) {
		currentFfmpegExecuter.execute(new File[]{file});
	}
	
	public void updateSettingTable(){
		List list=GenericParametersTableViewer.loadList(Akj_betasPlugin.getDefault().getPreferenceStore().getString(getPreferenceKey()+"."+FFMpegDropSomethingTab.SETTINGS));
		
		tableViewer.setGenericParametersList(list);
		
		
		//now if date is updated,selection is null,so i have to set manually.
				if(tableViewer.getTable().getItemCount()>0){
					tableViewer.getTable().setSelection(0);
					tableSelectionChanged();
					}
	}
	public class PreferenceStoreMonitor implements IPropertyChangeListener {

		public void propertyChange(PropertyChangeEvent event) {
			log.info(event.getProperty());
			if (event.getProperty().equals(getPreferenceKey()+"."+FFMpegDropSomethingTab.SETTINGS)) {
				updateSettingTable();
			}
		}
	}
	
	public void afterConvert() {
		// TODO Auto-generated method stub
		
	}
	
	//overwrite only work when ffmpeg is available
	public boolean isCanConvert(){
		
		String ffmpegPath = FFMpegUI.getFFmpegOrPureFFMpeg();

		if (!FFMpegUI.isFFMpegOrPureFFMpegAvailable(ffmpegPath)) {
			setCantConvertStatusbarMessage(Messages.getString("ffmpeg_statusbar.no_ffmpeg"));
		return false;
		}
		
		//check export setting.
		
		return super.isCanConvert();
	}

	public void cancelConvert() {
		currentFfmpegExecuter.cancel();
	}

	public void updateStatus() {
		if(samefolder!=null){
		if(samefolder.getSelection() || directoryChooser.getFile()!=null){
			setMessage(Messages.getString("dropsomething.drag_folder"));
			setCanConvert(true);
		}else{
			setErrorMessage(Messages.getString("dropsomething.choose_folder"));
			setCantConvertStatusbarMessage(Messages.getString("dropsomething.choose_folder"));
			setCanConvert(false);
		}
		}
	}
	
	public void setMessage(String text){
		if(dragHere!=null){//before initialize
		dragHere.setForeground(new Color(null,64,255,64));
		dragHere.setText(text);
		}
	}
	public void setErrorMessage(String text){
		if(dragHere!=null){
		dragHere.setForeground(new Color(null,255,0,0));
		dragHere.setText(text);
		}
	}

	public IPreferenceStore getPreferenceStore(){
		return Akj_betasPlugin.getDefault().getPreferenceStore();
	}
	
	public boolean setFocus(){
		return tableViewer.getTable().setFocus();
	}

	public FFMpegExecuter getFFMpegExecuter() {
		return currentFfmpegExecuter;
	}

	public FileOverwriteControler getFileOverWriteControler() {
		if(fileOverwriteControler==null){
			fileOverwriteControler=new FileOverwriteControler(this.getViewPart().getViewSite().getShell());
		}
		return fileOverwriteControler;
	}
	

	//do overwrite;
	/* TODO think
	public DropsomethingAction getAfterDropSomethingAction(GenericParametersFFMpegPreference preference){
		return null;
	}*/
	
	public void beforeConvert() {
		currentFfmpegExecuter = new FFMpegExecuter();
		Map newMap=editor.getParameters();//editor has only parameters which editor can handle
		GenericParameters setting=new GenericParameters(newMap);
		
		GenericParameters baseGeneric=null;
		int selection=tableViewer.getTable().getSelectionIndex();
		if(selection>=0){
			baseGeneric=(GenericParameters) tableViewer.getTable().getItem(tableViewer.getTable().getSelectionIndex()).getData();
		}else{
			baseGeneric=new GenericParameters();
		}
		
		
		
		
		preference = new GenericParametersFFMpegPreference(setting);
		
		String ffmpegPath = FFMpegUI.getFFmpeg();
		
		if(ffmpegPath==null){//if no ffmpeg anyway use pure ffmpeg
			ffmpegPath=FFMpegUI.getPureFFmpeg();
		}else{
			//if pure_ffmpeg is null use ffmpeg anyway
			if(FFMpegUI.getPureFFmpeg()!=null && FFMpegUI.isUsePureFFMpeg()){
			String ac=preference.getAudioCodec();
			String vc=preference.getVideoCodec();
			
			if(ac==null){
				ac=FFMpegUtils.getDefaultAudioCodec(preference.getFormat(),preference.getExtension());
			}
			
			if(vc==null){
				vc=FFMpegUtils.getDefaultVideoCodec(preference.getFormat(),preference.getExtension());
			}
			
			if(FFMpegUtils.isAudioOnlyExtension(preference.getExtension())){
				log.info("audio only");
				 //check audio only
				if(FFMpegUI.isPureFFMpegSupportedAudioCodec(ac)){
					
						ffmpegPath=FFMpegUI.getPureFFmpeg();
						log.info("use pure_ffmpeg");
					}
				
			}else{
				if(!preference.isEnableAudio()){
					log.info("video only");
					//check video only
					if(vc!=null &&FFMpegUI.isPureFFMpegSupportedVideoCodec(vc)){
						if(FFMpegUI.getPureFFmpeg()!=null){
						ffmpegPath=FFMpegUI.getPureFFmpeg();
						log.info("use pure_ffmpeg");
						}
					}
				}else{
					log.info("audio and video");
					//check video and audio
					if(ac!=null && FFMpegUI.isPureFFMpegSupportedAudioCodec(ac) && vc!=null &&FFMpegUI.isPureFFMpegSupportedVideoCodec(vc)){
						if(FFMpegUI.getPureFFmpeg()!=null){
						ffmpegPath=FFMpegUI.getPureFFmpeg();
						log.info("use pure_ffmpeg");
						}
					}
				}
			}
		}
		}
		
		
		preference.setFfmpegPath(ffmpegPath);
		
		
		
		log.info(preference);
		//log.info(tableViewer);
		//log.info(setting);
		//log.info(tableViewer.toLabel(setting));
		setHeaderText(tableViewer.toLabel(baseGeneric));//because setting has no name and comment
		
		DefaultFFMpegMonitor monitor=new DefaultFFMpegMonitor(this,getPreferenceKey());
		
		//monitor.setAfterAction(getAfterDropSomethingAction(preference));
		
		//set after actions
		String after_action=setting.getParameters().get(GenericParametersFFMpegPreference.AFTER_ACTION);
		//log.trace("after_action:"+after_action);
		if(after_action!=null && !after_action.equals("")){
			try {
				DropsomethingAction action=(DropsomethingAction) Class.forName(after_action).newInstance();
				monitor.setAfterAction(action);
				//log.trace("action:"+action.getClass().getName());
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		currentFfmpegExecuter.setExecuteListener(monitor);
		
		
		//support thread when h264.
		boolean threads = FFMpegUI.isUseThread();
		if(threads){
			if(FFMpegOptions.CODEC_VIDEO_H264.equals(preference.getVideoCodec())||FFMpegOptions.CODEC_VIDEO_LIB_X264.equals(preference.getVideoCodec())){
				preference.setThreads(2);//set thread only h264 or libx264
			}
		}
		
		currentFfmpegExecuter.setFfmpegPreference(preference);
		//
		String b=setting.getParameters().get(DropFileGenericParameterSetting.USE_AVISYNTH);
		boolean useAvisynth=false;
		if(b!=null && b.equals("1")){
			useAvisynth=true;
		}
		log.trace("ab:"+useAvisynth);
		currentFfmpegExecuter.setUseAvisynth(useAvisynth);
		
		currentFfmpegExecuter.setIgnoreAvisynthExtensions(new String[0]);//depend on
		
		
		currentFfmpegExecuter.setSameDirectory(samefolder.getSelection());
		currentFfmpegExecuter.setBackup(backup.getSelection());
		if(!samefolder.getSelection()){
			currentFfmpegExecuter.setExportDir(directoryChooser.getAbsoluteFilePath());
		}
		
	}
}
